package com.cbg.runner;

import cn.hutool.cron.CronUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cbg.base.constant.Constant;
import com.cbg.sys.entity.*;
import com.cbg.sys.service.*;
import com.cbg.sys.utils.LineUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
/**
 * <pre></pre>
 * <small> 2018-12-13 | chenbing </small>
 */
@Component
@Transactional
public class StartRunner implements CommandLineRunner {
    private static final Logger log= LoggerFactory.getLogger(StartRunner.class);

    @Autowired
    StringRedisTemplate counter;
    @Autowired
    RedisTemplate<String, Route> routeRedisTemplate;
    @Autowired
    RedisTemplate<String, Line> lineRedisTemplate;
    @Autowired
    IRouteService routeService;
    @Autowired
    ILineService lineService;
    @Autowired
    ILineIniService iniService;
    @Autowired
    ILineCarService lineCarService;

    @Override
    public void run(String... args){
        log.info(">>>>>>>>>>>>>>>服务启动，等待加载资源<<<<<<<<<<<<<");

        log.info(">>>>>>>>>>>>>>>开始缓存路线资源<<<<<<<<<<<<<");
        cacheRoutes();
        log.info(">>>>>>>>>>>>>>>路线资源缓存完毕!<<<<<<<<<<<<<");

        log.info(">>>>>>>>>>>>>>>开始缓存今明后三天排班资源<<<<<<<<<<<<<");
        cacheLinesIn3Days();
        log.info(">>>>>>>>>>>>>>>排班资源缓存完毕!<<<<<<<<<<<<<");

        log.info(">>>>>>>>>>>>>>>开启定时任务<<<<<<<<<<<<<");
        CronUtil.setMatchSecond(true);
        CronUtil.start();
        log.info(">>>>>>>>>>>>>>>定时任务开启成功!<<<<<<<<<<<<<");

        log.info(">>>>>>>>>>>>>>>资源全部加载完毕!!!<<<<<<<<<<<<<");
    }

    /**
     * 启动时，缓存全部路线
     */
    private void cacheRoutes(){
        routeRedisTemplate.delete(Constant.ROUTE_KEY);
        routeRedisTemplate.opsForList().leftPushAll(Constant.ROUTE_KEY,routeService.list());
    }

    /**
     * 启动时，缓存3天的班次
     */
    private void cacheLinesIn3Days(){
        lineRedisTemplate.delete(lineRedisTemplate.keys(Constant.LINE_SUFFIX+"*"));
        Map<String, Map<Integer, List<Line>>> lines = lineService.linesOf3Days();
        Set<String> routeSet;
        //若是第一次启动
        if((routeSet = lines.keySet()).size()==0) {
            createLinesIn3DaysByIni();
        }else {
            //若MySQL中已排天数不足3天
            for(String routeId:routeSet){
                if(lines.get(routeId).size()<Constant.TOTAL_DAYS){
                    List<String> msDelIds = lineService.list(new LambdaQueryWrapper<Line>().between(Line::getDateIn, LocalDate.now(), LocalDate.now().plusDays(1)))
                            .parallelStream().map(Line::getId).collect(Collectors.toList());
                    lineService.removeByIds(msDelIds);
                    counter.delete(counter.keys(Constant.TYPE_SUFFIX+"*"));
                    lineCarService.removeByIds(msDelIds);
                    List<LineIni> lineInis = iniService.list(new LambdaQueryWrapper<LineIni>()
                            .between(LineIni::getDateIn, LocalDate.now(), LocalDate.now().plusDays(1)))
                            .stream().map(x -> x.setIsDone(false)).collect(Collectors.toList());
                    if(lineInis.size()>0)
                        iniService.updateBatchById(lineInis);
                    lineService.updateBatchById(lineService.list());
                    createLinesIn3DaysByIni();
                    break;
                }
            }
        }
        lines=lineService.linesOf3Days();
        LineUtils.putLinesIn3DaysToRedis(lines);
    }

    /**
     * 根据ini表创建3天的line
     */
    private void createLinesIn3DaysByIni(){
        //3天之内的临时排班，可能为0天/1天/2天/3天，同一天的排班配置可能有多个
        List<LineIni> lsInis = new LineIni().selectList(new LambdaQueryWrapper<LineIni>().eq(LineIni::getType, 2)
                .eq(LineIni::getIsDone, 0).between(LineIni::getDateIn, LocalDate.now(), LocalDate.now().plusDays(2)));
        LongStream.rangeClosed(0,2).forEach(x->{
            LocalDate eachDay = LocalDate.now().plusDays(x);
            List<Line> lines;
            if(lsInis.stream().anyMatch(e->eachDay.equals(e.getDateIn()))){
                //临时排班
                lines = LineUtils.createLinesByInis(lsInis.stream().filter(c -> eachDay.equals(c.getDateIn())).collect(Collectors.toList()), eachDay);
            }else {
                //普通或周末排班
                List<LineIni> inis=iniService.list(new LambdaQueryWrapper<LineIni>()
                        .eq(LineIni::getType, eachDay.getDayOfWeek().getValue() < 6 ? 0 : 1));
                if(inis.size()==0&&eachDay.getDayOfWeek().getValue()>5)
                    inis=iniService.list(new LambdaQueryWrapper<LineIni>().eq(LineIni::getType, 0));
                lines = LineUtils.createLinesByInis(inis, eachDay);
            }
            if(lines.size()>0)
                lineService.saveOrUpdateBatch(lines);
            lineCarService.planTypeAndCar(lines);
        });
    }
}
